package com.hk.core.authentication.api.validatecode;

import com.hk.commons.util.AssertUtils;
import com.hk.commons.util.ClassUtils;

import java.io.IOException;
import java.util.Objects;

/**
 * @author kevin
 * @date 2018-07-27 13:44
 */
public abstract class AbstractValidateCodeProcessor<C extends ValidateCode> implements ValidateCodeProcessor<C> {

    /**
     * 验证码生成器
     */
    private final ValidateCodeGenerator<C> validateCodeGenerator;

    private final Class<C> validateCodeClass;

    /**
     * 验证码存储器
     */
    private final ValidateCodeStrategy<C> validateCodeStrategy;

    protected AbstractValidateCodeProcessor(ValidateCodeGenerator<C> validateCodeGenerator,
                                            ValidateCodeStrategy<C> validateCodeStrategy) {
        this.validateCodeGenerator = validateCodeGenerator;
        this.validateCodeStrategy = validateCodeStrategy;
        this.validateCodeClass = ClassUtils.getGenericType(validateCodeGenerator.getClass(), 0);
        AssertUtils.notNull(this.validateCodeClass, "validateCodeClass is null.");
    }

    @Override
    public C create(C validateCode) throws IOException {
        var result = validateCodeGenerator.generate(validateCode);
        validateCodeStrategy.save(result);
        send(result);
        return result;
    }

    /**
     * 发送验证码
     *
     * @param validateCode 验证码
     * @param request      request
     */
    protected void send(C validateCode) throws IOException {

    }

    /**
     * 验证验证码
     *
     * @param request request
     */
    @Override
    public void validate(C validateCode) {
        var inStoreValidateCode = validateCodeStrategy.get(validateCode, validateCodeClass);
        AssertUtils.notNull(inStoreValidateCode, () -> new ValidateCodeException(validateCode, "验证码不存在"));
        if (inStoreValidateCode.isExpired()) {
            validateCodeStrategy.remove(validateCode);
            throw new ValidateCodeException(validateCode, "验证码已过期");
        }
        AssertUtils.notEmpty(inStoreValidateCode.getCode(), () -> new ValidateCodeException(validateCode, "验证码不能为空"));
        AssertUtils.isTrue(Objects.equals(inStoreValidateCode.getCode(), validateCode.getCode()), () -> new ValidateCodeException(validateCode, "验证码错误"));
        validateCodeStrategy.remove(validateCode);
    }
}
